home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
comms
/
pipeln10.zip
/
AQUEDUCT.ASM
next >
Wrap
Assembly Source File
|
1990-06-01
|
12KB
|
386 lines
;**************************************************************************
;* AQUEDUCT vers 1.20, DOS *
;* Connects COM1 and COM2 in software. *
;* 6/1/90 *
;* by James W. Birdsall *
;* *
;* assembles under Turbo Assembler 1.0, 2.0 *
;* *
;* requires DOS 2.0 or higher *
;* *
;* This program is a small TSR that connects COM1 and COM2 in software. *
;* It is run from the command line with no arguments. After *
;* installation, setup and activation is performed with the program *
;* VALVE. *
;* *
;* This program can share an interrupt vector. It can be set to chain *
;* to the previous interrupt handler if examination of the serial port *
;* shows that no interrupt is pending. *
;* *
;**************************************************************************
LOCALS
.MODEL tiny
ENVOFFSET EQU 2Ch
INTERFACEINT EQU 0F1h
BUFFERLENGTH EQU 8
BUFFERLENMASK EQU 08h
BUSY1READ EQU 01h
BUSY1SEND EQU 02h
BUSY2READ EQU 04h
BUSY2SEND EQU 08h
; TO CHANGE FROM COM1 OR COM2, CHANGE THE FOLLOWING INTERRUPT AND PORT
; VALUES.
COM1INT EQU 0Ch
COM2INT EQU 0Bh
COM1BASE EQU 3F8h
COM1IER EQU 3F9h
COM1IIR EQU 3FAh
COM1LSR EQU 3FDh
COM2BASE EQU 2F8h
COM2IER EQU 2F9h
COM2IIR EQU 2FAh
COM2LSR EQU 2FDh
; END OF INTERRUPT AND PORT VALUES
EOI EQU 20h
EOIPORT EQU 20h
RDAINT EQU 04h
THREINT EQU 02h
RDAENABLE EQU 01h
BOTHENABLE EQU 03h
OVERRUNMASK EQU 02h
INTPENDMASK EQU 01h
.CODE
ORG 100h
start:
jmp Install ; jump to installation code
; DATA AREA
errors dw 0
int_B dd 0
old_int_B dd 0
int_C dd 0
old_int_C dd 0
PSPseg dw 0
old_interface dd 0
enabled db 0
chain db 0
one_in_head dw 0
one_in_tail dw 0
two_in_head dw 0
two_in_tail dw 0
busyflag db 0
one_in db BUFFERLENGTH dup (?)
two_in db BUFFERLENGTH dup (?)
; HANDLER FOR COM1 INTERRUPTS
Com1handler:
sti ; enable interrupts
push ax ; preserve
push bx
push dx
mov dx, COM1LSR ; check for overruns
in al, dx
test al, OVERRUNMASK
jz @@NoOverrun ; if zero, OK
inc cs:errors ; else increment ERRORS
@@NoOverrun:
mov dx, COM1IIR ; read interrupt id
in al, dx
test al, INTPENDMASK ; is our interrupt?
jz @@Ours ; if zero, ours
jmp @@NotOurs ; else not
@@Ours:
cmp al, RDAINT ; is received char?
je @@Received
cmp al, THREINT ; is send?
je @@Transmit
jmp @@SendEOI ; if unknown, send EOI
@@Received:
mov dx, COM1BASE ; read character
in al, dx
test cs:busyflag, BUSY2SEND ; is port 2 sending?
jz @@OkToRead ; if zero, go ahead
inc cs:errors ; else increment errors
jmp @@SendEOI ; and send EOI
@@OkToRead:
or cs:busyflag, BUSY1READ ; set flag
mov bx, cs:one_in_head ; get index
mov cs:one_in + bx, al ; put char in buffer
inc cs:one_in_head ; increment index
test cs:one_in_head, BUFFERLENMASK ; check for index overflow
jz @@ReadDone ; if no overflow, jump
mov cs:one_in_head, 0 ; else zero index
@@ReadDone:
mov dx, COM2IER ; read interrupt enable
in al, dx
cmp al, BOTHENABLE ; THRE already on?
je @@ReadDone2 ; do nothing
mov al, BOTHENABLE ; else enable it
xor cs:busyflag, BUSY1READ ; reset flag just before enabling int
out dx, al
jmp @@SendEOI ; and jump
@@ReadDone2:
xor cs:busyflag, BUSY1READ ; reset flag
jmp @@SendEOI
@@Transmit:
test cs:busyflag, BUSY2READ ; is port 2 reading?
jz @@OkToSend ; if zero, go ahead
or cs:busyflag, BUSY1SEND
jmp @@NoTrans ; otherwise shut down sending
@@OkToSend:
or cs:busyflag, BUSY1SEND ; set flag
mov bx, cs:two_in_tail ; set index
cmp bx, cs:two_in_head ; are chars to send?
je @@NoTrans ; if not, shut down sending
mov al, cs:two_in + bx ; else move char to AL
mov dx, COM1BASE
out dx, al
inc cs:two_in_tail ; increment index
test cs:two_in_tail, BUFFERLENMASK ; check for overflow
jz @@SentOK ; if no overflow, jump
mov cs:two_in_tail, 0 ; else zero index
@@SentOK:
xor cs:busyflag, BUSY1SEND ; reset flag
jmp @@SendEOI
@@NoTrans:
mov dx, COM1IER ; read interrupt enable
in al, dx
cmp al, RDAENABLE ; RDA only already?
je @@NoTrans2 ; if so, do nothing
mov al, RDAENABLE ; else enable RDA only
out dx, al
jmp @@NoTrans2 ; and jump
@@NoTrans2:
xor cs:busyflag, BUSY1SEND ; reset flag
jmp @@SendEOI ; and jump
@@NotOurs:
test cs:chain, 0FFh ; is chain zero?
jz @@SendEOI ; if so, return normally
pushf ; preserve flags
call cs:old_int_C ; call old handler
jmp @@Final ; and return
@@SendEOI:
mov al, EOI ; send EOI
out EOIPORT, al
@@Final:
pop dx ; restore
pop bx
pop ax
iret ; return
; HANDLER FOR COM2 INTERRUPTS
Com2handler:
sti ; enable interrupts
push ax ; preserve
push bx
push dx
mov dx, COM2LSR ; check for overruns
in al, dx
test al, OVERRUNMASK
jz @@NoOverrun ; if zero, OK
inc cs:errors ; else increment ERRORS
@@NoOverrun:
mov dx, COM2IIR ; read interrupt id
in al, dx
test al, INTPENDMASK ; is our interrupt?
jz @@Ours ; if zero, ours
jmp @@NotOurs ; else not
@@Ours:
cmp al, RDAINT ; is received char?
je @@Received
cmp al, THREINT ; is send?
je @@Transmit
jmp @@SendEOI ; if unknown, send EOI
@@Received:
mov dx, COM2BASE ; read character
in al, dx
test cs:busyflag, BUSY1SEND ; is port 1 sending?
jz @@OkToRead ; if zero, go ahead
inc cs:errors ; else increment errors
jmp @@SendEOI ; and send EOI
@@OkToRead:
or cs:busyflag, BUSY2READ ; set flag
mov bx, cs:two_in_head ; get index
mov cs:two_in + bx, al ; put char in buffer
inc cs:two_in_head ; increment index
test cs:two_in_head, BUFFERLENMASK ; check for index overflow
jz @@ReadDone ; if no overflow, jump
mov cs:two_in_head, 0 ; else zero index
@@ReadDone:
mov dx, COM1IER ; read interrupt enable
in al, dx
cmp al, BOTHENABLE ; THRE already on?
je @@ReadDone2 ; do nothing
mov al, BOTHENABLE ; else enable it
out dx, al
jmp @@ReadDone2 ; and jump
@@ReadDone2:
xor cs:busyflag, BUSY2READ ; reset flag
jmp @@SendEOI ; and jump
@@Transmit:
test cs:busyflag, BUSY1READ ; is port 1 reading?
jz @@OkToSend ; if zero, go ahead
or cs:busyflag, BUSY2SEND ; set flag
jmp @@NoTrans ; otherwise shut down sending
@@OkToSend:
or cs:busyflag, BUSY2SEND ; set flag
mov bx, cs:one_in_tail ; set index
cmp bx, cs:one_in_head ; are chars to send?
je @@NoTrans ; if not, shut down sending
mov al, cs:one_in + bx ; else move char to AL
mov dx, COM2BASE
out dx, al
inc cs:one_in_tail ; increment index
test cs:one_in_tail, BUFFERLENMASK ; check for overflow
jz @@SentOK ; if no overflow, jump
mov cs:one_in_tail, 0 ; else zero index
jmp @@SentOK ; and jump
@@SentOK:
xor cs:busyflag, BUSY2SEND ; reset flag
jmp @@SendEOI
@@NoTrans:
mov dx, COM2IER ; read interrupt enable
in al, dx
cmp al, RDAENABLE ; RDA only already?
je @@NoTrans2 ; if so, do nothing
mov al, RDAENABLE ; else enable RDA only
out dx, al
jmp @@NoTrans2 ; and jump
@@NoTrans2:
xor cs:busyflag, BUSY2SEND ; reset flag
jmp @@SendEOI ; and jump
@@NotOurs:
test cs:chain, 0FFh ; is chain zero?
jz @@SendEOI ; if so, return normally
pushf ; preserve flags
call cs:old_int_B ; call old handler
jmp @@Final ; and return
@@SendEOI:
mov al, EOI ; send EOI
out EOIPORT, al
@@Final:
pop dx ; restore
pop bx
pop ax
iret ; return
; SIGNATURE USED FOR INSTALLATION CHECK
signature db 'JWBA12'
; INTERFACE INTERRUPT HANDLER -- RETURNS POINTER TO DATA AREA
Interface:
mov ax, cs ; put segment in AX
mov bx, offset errors ; put offset in BX
iret ; and return
; INSTALLATION CODE -- IS DISCARDED AFTER INSTALLATION
Last_byte:
OKmessage db 'AQUEDUCT installed OK.',0Dh,0Ah,'$'
FAILmessage db 'AQUEDUCT installation error.',0Dh,0Ah,'$'
COPYRIGHT db 'Copyright (c) 1990 James W. Birdsall.'
COPYRIGHT2 db 'All Rights Reserved.'
Install:
mov bx, es ; copy PSP segment from ES to BX
mov PSPseg, bx ; put into storage
mov si, ENVOFFSET
mov ax, es:si ; move environment segment into AX
or ax, ax ; check it
jz Continue ; if zero, no environment
mov es, ax ; put env seg in ES
mov ah, 49h ; free block
int 21h
jc Fail ; if carry set, error
Continue:
; put far ptrs to handlers in storage
mov WORD PTR [int_B], offset Com2handler
mov WORD PTR [int_C], offset Com1handler
mov ax, cs
mov WORD PTR [int_B+2], ax
mov WORD PTR [int_C+2], ax
mov ah, 35h ; get old int 0Bh vector
mov al, 0Bh
int 21h
mov WORD PTR [old_int_B], bx ; and put in old_int_B
mov bx, es
mov WORD PTR [old_int_B+2], bx
mov ah, 35h ; get old int 0Ch vector
mov al, 0Ch
int 21h
mov WORD PTR [old_int_C], bx ; and put in old_int_C
mov bx, es
mov WORD PTR [old_int_C+2], bx
mov ah, 35h ; get old interface vector
mov al, INTERFACEINT
int 21h
mov WORD PTR [old_interface], bx ; and put in old_interface
mov bx, es
mov WORD PTR [old_interface+2], bx
mov ah, 25h ; set up interface
mov al, INTERFACEINT
mov dx, offset Interface
int 21h
mov ah, 09h ; print OK message
mov dx, offset OKmessage
int 21h
mov dx, offset Last_byte ; go resident with code 0
add dx, 15
mov cl, 4
shr dx, cl
mov ah, 31h
xor al, al
int 21h
Fail:
mov ah, 09h ; print FAIL message
mov dx, offset FAILmessage
int 21h
mov ah, 4Ch ; exit with code 3
mov al, 3
int 21h
END start
END